package free.play.controller;

import static org.springframework.util.StringUtils.isEmpty;

import free.play.entity.Role;
import free.play.entity.User;
import free.play.model.PagedResource;
import free.play.model.request.CreateUserRequest;
import free.play.model.request.UpdateUserRequest;
import free.play.model.response.UserResponse;
import free.play.repository.RoleRepository;
import free.play.repository.UserRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.ArrayList;
import java.util.List;

@Controller
@RequestMapping("users")
public class UserController {

  @Autowired
  private UserRepository userRepository;

  @Autowired
  private RoleRepository roleRepository;

  @Transactional
  @RequestMapping(method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE,
      MediaType.APPLICATION_XML_VALUE})
  public ResponseEntity<?> getAll(@PageableDefault(sort = {"name"}) Pageable pageable) {

    Page<User> findAll = userRepository.findAll(pageable);
    doSomething();
    List<UserResponse> userResponse = new ArrayList<>();
    for (User user : findAll.getContent()) {
      UserResponse response = new UserResponse();
      BeanUtils.copyProperties(user, response);
      userResponse.add(response);
    }
    PagedResource<UserResponse> response =
        new PagedResource<>(userResponse, findAll.getSize(), findAll.getNumber(),
            findAll.getTotalElements(), findAll.getTotalPages());
    return new ResponseEntity<>(response, HttpStatus.OK);
  }

  private void doSomething() {

  }

  @RequestMapping(method = RequestMethod.POST, consumes = {MediaType.APPLICATION_JSON_VALUE,
      MediaType.APPLICATION_XML_VALUE}, produces = {MediaType.TEXT_PLAIN_VALUE,
      MediaType.APPLICATION_JSON_VALUE})
  public ResponseEntity<?> create(@RequestBody CreateUserRequest request) {

    List<String> errors = validateCreateRequest(request);
    if (errors.size() > 0) {
      return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
    }

    User user = new User();
    BeanUtils.copyProperties(request, user);

    for (int i = 0; i < 3; i++) {
      Role role = new Role();
      role.setName("role");
      user.getRoles().add(role);
    }
    userRepository.save(user);

    return new ResponseEntity<>(user.getId(), HttpStatus.CREATED);
  }

  @RequestMapping(value = "{id}", method = RequestMethod.PATCH)
  @Transactional
  public ResponseEntity<?> patch(@PathVariable String id, @RequestBody UpdateUserRequest request) {

    List<String> errors = validateUpdateRequest(request);
    if (errors.size() > 0) {
      return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
    }
    User findOne = userRepository.findOne(id);
    if (findOne == null) {
      return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }
    BeanUtils.copyProperties(request, findOne);
    if (findOne.getRoles().size() > 0) {
      findOne.getRoles().remove(0);
    }
    userRepository.save(findOne);

    return new ResponseEntity<>(HttpStatus.OK);
  }

  @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
  public ResponseEntity<?> delete(@PathVariable String id) {

    User findOne = userRepository.findOne(id);
    if (findOne == null) {
      return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
    }
    userRepository.delete(findOne);
    return new ResponseEntity<>(HttpStatus.OK);
  }

  private List<String> validateCreateRequest(CreateUserRequest request) {

    List<String> errors = new ArrayList<>();
    if (isEmpty(request.getLoginName())) {
      errors.add("Login name can not be empty");
    }
    if (userRepository.findByLoginName(request.getLoginName()) != null) {
      errors.add("Please choose another login name");
    }
    if (isEmpty(request.getName())) {
      errors.add("Name can not be empty");
    }
    if (isEmpty(request.getPassword())) {
      errors.add("Password can not be empty");
    }
    return errors;
  }

  private List<String> validateUpdateRequest(UpdateUserRequest request) {

    List<String> errors = new ArrayList<>();
    if (isEmpty(request.getName())) {
      errors.add("Name can not be empty");
    }
    return errors;
  }

}
